package capricornus.scene
{
	import capricornus.actor.Actor;
	import capricornus.actor.Avatar;
	import capricornus.actor.Monster;
	import capricornus.actor.NPC;
	import capricornus.actor.NonePlayer;
	import capricornus.actor.Player;
	import capricornus.actor.events.ActorEvent;
	import capricornus.core.RefreshManager;
	import capricornus.core.StageManager;
	import capricornus.events.RefreshEvent;
	import capricornus.events.StageEvent;
	import capricornus.scene.controller.ActionSceneBackController;
	import capricornus.scene.controller.ActionSceneDataController;
	import capricornus.scene.events.ActionSceneEvent;
	import capricornus.scene.preload.ScenePreLoadController;
	import capricornus.scene.preload.ScenePreLoadEvent;
	import capricornus.scene.sceneio.ActionSceneInteractiveController;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	
	[Event(name="actionSceneScrolled", type="capricornus.scene.events.ActionSceneEvent")]
	[Event(name="actionSceneDataComplete", type="capricornus.scene.events.ActionSceneEvent")]
	public class AbstractScene extends Sprite
	{
		private var _dictActor:Dictionary = new Dictionary();
		
		private var _id:String;
		private var _width:int;   //场景宽度
		private var _height:int;
		private var _viewWidth:int;  //视口宽度
		private var _viewHeight:int;
		
		protected var _preLoadController:ScenePreLoadController;
		
		protected var _isViewPortDragging:Boolean = false;
		protected var _watchTarget:Actor;
		protected var _rectViewPort:Rectangle;
		
		protected var _backController:ActionSceneBackController;
		protected var _dataController:ActionSceneDataController;
		protected var _interactiveController:ActionSceneInteractiveController;
		
		private var _backLayer:Sprite;
		private var _skillBottomLayer:Sprite;
		private var _actorLayer:Sprite;
		private var _skillTopLayer:Sprite;
		
		public function AbstractScene()
		{
			super();
			init();
		}
		
		private function init():void
		{
			_dictActor = new Dictionary();
			
			this.mouseEnabled = false;
			
			_backLayer = new Sprite();
			_backLayer.mouseChildren = false;
			addChild( _backLayer );
			
			_skillBottomLayer = new Sprite();
			_skillBottomLayer.mouseChildren = false;
			_skillBottomLayer.mouseEnabled = false;
			addChild( _skillBottomLayer );
			
			_actorLayer = new Sprite();
			_actorLayer.mouseChildren = false;
			_actorLayer.mouseEnabled = false;
			addChild( _actorLayer );
			
			_skillTopLayer = new Sprite();
			_skillTopLayer.mouseChildren = false;
			_skillTopLayer.mouseEnabled = false;
			addChild( _skillTopLayer );
			
			_preLoadController = new ScenePreLoadController( this );
			
			_backController = new ActionSceneBackController( _backLayer );
			_dataController = new ActionSceneDataController( this );
			_interactiveController = new ActionSceneInteractiveController( this );
			
			_backController.addEventListener( Event.COMPLETE, onBackImageComplete, false, 0, true );
			_preLoadController.addEventListener( ScenePreLoadEvent.SCENE_PRELOAD_COMPLETE, onScenePreLoadComplete, false, 0, true );
			StageManager.instance.addEventListener( StageEvent.RESIZE, onStageResize, false, 0, true );
			
			this.addEventListener( MouseEvent.MOUSE_OUT, onSceneMouseOut, false, 0, true );
			this.addEventListener( MouseEvent.MOUSE_OVER, onSceneMouseOver, false, 0, true );
			_backLayer.addEventListener( MouseEvent.CLICK, onAvatarMove, false, 0, true );
			RefreshManager.instance.addEventListener( RefreshEvent.REFRESH, onRefresh, false, 0, true );
		}
		
		public function get backLayer():Sprite
		{
			return _backLayer;
		}
		
		public function get skillBottomLayer():Sprite
		{
			return _skillBottomLayer;
		}
		
		public function get actorLayer():Sprite
		{
			return _actorLayer;
		}
		
		public function get skillTopLayer():Sprite
		{
			return _skillTopLayer;
		}
		
		public function get preLoadController():ScenePreLoadController
		{
			return _preLoadController;
		}
		
		public function getActorByID( id:String ):Actor
		{
			return _dictActor[id];
		}
		
		public function addActor( actor:Actor ):void
		{
			var id:String = actor.attribute.id;
			if( _dictActor[id]==null )
			{
				_actorLayer.addChild( actor );
				actor.onAddToScene();
				_dictActor[id] = actor;
			}
		}
		
		public function removeActor( actor:Actor ):void
		{
			var id:String = actor.attribute.id;
			if( _dictActor[id] != null )
			{
				_actorLayer.removeChild( actor );
				actor.onRemoveFromScene();
				delete _dictActor[id];
			}
		}
		
		public function removeActorByID( id:String ):void
		{
			var actor:Actor = _dictActor[id] as Actor;
			if( actor != null )
			{
				delete _dictActor[id];
				_actorLayer.removeChild( actor );
			}
		}
		
		public function startViewPortDrag():void
		{
			_isViewPortDragging = true;
		}
		
		/**
		 * 设置当前视口中心--处理小地图拖动 
		 * @param pt
		 * 
		 */		
		public function setViewPortCenterPoint( pt:Point ):void
		{
			var x:int = pt.x;
			var y:int = pt.y;
			
			_rectViewPort.x = int(x - _viewWidth/2);
			if( _rectViewPort.x < 0 ) _rectViewPort.x = 0;
			if( _rectViewPort.x + _viewWidth > _width ) _rectViewPort.x = _width - _viewWidth;
			
			_rectViewPort.y = int(y - _viewHeight/2);
			if( _rectViewPort.y < 0 ) _rectViewPort.y = 0;
			if( _rectViewPort.y + _viewHeight > _height ) _rectViewPort.y = _height - _viewHeight;
			
			this.scrollRect = _rectViewPort;
		}
		
		public function stopViewPortDrag():void
		{
			_isViewPortDragging = false;
		}
		
		/**
		 * 场景跟随中心对象，一般为Avatar 
		 * @param actor
		 * 
		 */		
		public function set watchTarget( actor:Actor ):void
		{
			if( _watchTarget != actor )
			{
				if( _watchTarget != null )
				{
					_watchTarget.removeEventListener( ActorEvent.MOVED, onWatchTargetMoved );
				}
				_watchTarget = actor;
				if( _watchTarget != null )
				{
					onWatchTargetMoved(null);
					_watchTarget.addEventListener( ActorEvent.MOVED, onWatchTargetMoved, false, 0, true );
				}
			}
		}
		
		public function get viewPort():Rectangle
		{
			return _rectViewPort;
		}
		
		override public function set scrollRect(value:Rectangle):void
		{
			if( this.scrollRect != null && value.equals( this.scrollRect ) ) return;
			
			super.scrollRect = value;
			if( _backController != null )
			{
				_backController.sceneScrollRectChange( value );
			}
			
			dispatchEvent( new ActionSceneEvent( ActionSceneEvent.ACTION_SCENE_SCROLLED, value ) );
		}
		
		public function test():void
		{
			_width = 10000;
			_height = 10000;
			_backController.reset( "1" );
			_rectViewPort = new Rectangle( 0, 0, StageManager.stageWidth, StageManager.stageHeight );
			onStageResize( null );
		}
		
		private var _currentFrame:int = 0;
		private function onRefresh( e:RefreshEvent ):void
		{
			var rect:Rectangle = this.scrollRect;
			if( rect==null ) return;
			
			if( _currentFrame==0 )
			{
				for( var i:String in _dictActor )
				{
					var actor:Actor = _dictActor[i];
					actor.isHide( !rect.contains( actor.x, actor.y ) );
				}
			}
			_currentFrame++;
			if( _currentFrame > 3 ) _currentFrame = 0;
		}
		
		private function onWatchTargetMoved( e:ActorEvent ):void
		{
			if( _rectViewPort==null ) return;
			if( _isViewPortDragging ) return;
			
			var x:int = _watchTarget.x;
			var y:int = _watchTarget.y;
			
			_rectViewPort.x = int(x - _viewWidth/2);
			if( _rectViewPort.x < 0 ) _rectViewPort.x = 0;
			if( _rectViewPort.x + _viewWidth > _width ) _rectViewPort.x = _width - _viewWidth;
				
			_rectViewPort.y = int(y - _viewHeight/2);
			if( _rectViewPort.y < 0 ) _rectViewPort.y = 0;
			if( _rectViewPort.y + _viewHeight > _height ) _rectViewPort.y = _height - _viewHeight;
			
			this.scrollRect = _rectViewPort;
		}
		
		private function onStageResize( e:StageEvent ):void
		{
			_viewWidth = StageManager.stageWidth;
			_viewHeight = StageManager.stageHeight;
			
			if( _watchTarget != null && _rectViewPort != null )
			{
				_rectViewPort.width = _viewWidth;
				_rectViewPort.height = _viewHeight;
				
				onWatchTargetMoved( null );
			}
		}
		
		protected function resetFromBytes( byte:ByteArray ):void
		{
			var id:String = byte.readUTF();;
			if( id==_id ) return;
			clear();
			
			_id = id;
			_width = byte.readShort();
			_height = byte.readShort();
			
			_preLoadController.start( _id );
			
			onStageResize( null );
			_rectViewPort = new Rectangle( 0, 0, _viewWidth, _viewHeight );
			
			watchTarget = Avatar.instance;
			
			//其他玩家
			var len:int = byte.readUnsignedShort();
			while( len-- > 0 )
			{
				var p:Player = Player.createFromBytes( byte );
				addActor( p );
			}
			
			//npc，这个可以放到地图数据里面去
			len = byte.readUnsignedShort();
			while( len-- > 0 )
			{
				var npc:NPC = NPC.createFromBytes( byte );
				addActor( npc );
			}
			
			//怪物
			len = byte.readUnsignedShort();
			while( len-- > 0 )
			{
				var monster:Monster = Monster.createFromBytes( byte );
				addActor( monster );
			}
			
			//场景物件
			len = byte.readUnsignedShort();
			while( len-- > 0 )
			{
				var np:NonePlayer = NonePlayer.createFromBytes( byte );
				addActor( np );
			}
		}
		
		private function onBackImageComplete( e:Event ):void
		{
			//while( _previewLayer.numChildren > 0 ) _previewLayer.removeChildAt(0);
		}
		
		private function onScenePreLoadComplete( e:ScenePreLoadEvent ):void
		{
			_backController.reset( _id );
			_dataController.sceneIDChange( _id );
			
			dispatchEvent( new ActionSceneEvent( ActionSceneEvent.ENTER_SCENE ) );
		}
		
		protected function clear():void
		{
			for( var i:* in _dictActor )
			{
				var actor:Actor = _dictActor[i];
				delete _dictActor[i];
				actor.destroy();
			}
			
			dispatchEvent( new ActionSceneEvent( ActionSceneEvent.LEAVE_SCENE ) );
		}
		
		private function onSceneMouseOver( e:MouseEvent ):void
		{
			dispatchEvent( new ActionSceneEvent( ActionSceneEvent.ACTION_SCENE_MOUSE_OVER ) );
		}
		
		private function onSceneMouseOut( e:MouseEvent ):void
		{
			dispatchEvent( new ActionSceneEvent( ActionSceneEvent.ACTION_SCENE_MOUSE_OUT ) );
		}
		
		private function onAvatarMove( e:MouseEvent ):void
		{
			//控制主角移动
			Avatar.instance.addMovePath( [[Avatar.instance.x, Avatar.instance.y], [int(e.localX), int(e.localY)]] );
		}
	}
}












